package com.my.library.dao;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.jdbc.core.JdbcTemplate;

import com.my.library.entity.BaseModel;
import com.my.library.entity.EntityRowMapper;
import com.my.library.entity.Role;
import com.my.library.util.EntityTableMapping;
import com.my.library.util.StringUtil;

public class AbstractDAO<T extends BaseModel> {
	@Resource(name="jdbcTemplate")
	private JdbcTemplate jdbcTemplate;

	/**
	 * @return the jdbcTemplate
	 */
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	/**
	 * @param jdbcTemplate the jdbcTemplate to set
	 */
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	public String createXML(String[] heads, List<T> list, List<Map<String, Object>> functions) {
		Class<T> c = this.getGenericType();
		System.out.println(c);
		StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?><data>");
		sb.append("<head>");
		for(int i=1; i<heads.length; i++) {
			sb.append("<cell>").append(heads[i]).append("</cell>");
		}
		sb.append("</head>");
		sb.append("<content>");
		
		for(T t: list) {
			Object u = c.cast(t);
			sb.append("<entry>");
			try {
				/*sb.append("<cell>").append(u.getClass().getMethod("getId").invoke(u)).append("</cell>");
				for(String head: heads) {
					sb.append("<cell>").
					append(u.getClass().getMethod("get" + StringUtil.getFirstUpperName(head)).invoke(u)).
					append("</cell>");
				}*/
				
				for(String field: heads) {
					for(Field f: c.getDeclaredFields()) {
						String fieldName = EntityTableMapping.getTableOrFieldName(f);
						if(fieldName.equals(field)) {
							f.setAccessible(true);
							sb.append("<cell>").
							append(StringUtil.null2Empty(f.get(u))).
							append("</cell>");
							break;
						}
					}
				}
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			sb.append("</entry>");
		}
		
		sb.append("</content>");
		
		sb.append("<functions>");
		for(Map<String, Object> function: functions) {
			sb.append("<function name='" + StringUtil.null2Empty(function.get("name")) +
					"' url='" + StringUtil.null2Empty(function.get("url")) + "' visibility='" + 
							StringUtil.null2Empty(function.get("visibility")) +
							"' usability='" + StringUtil.null2Empty(function.get("usability")) + "' type='"
			+ StringUtil.null2Empty(function.get("type")) + "'>").append("</function>");
		}
		sb.append("</functions>");
		
		sb.append("</data>");
		
		System.out.println(sb.toString());
		return sb.toString();

	}
	
	public Class getGenericType() {
		ParameterizedType p = (ParameterizedType) this.getClass().getGenericSuperclass();
		System.out.println(Arrays.toString(p.getActualTypeArguments()));
		return (Class) p.getActualTypeArguments()[0];
	}
	
	public String getContentSql(String tableName, String[] fields, String condition) {
		String contentSql = "select ";
		for(String field: fields) {
			contentSql = contentSql + field + ",";
		}
		contentSql = contentSql.substring(0, contentSql.length()-1) + " from " + tableName + " " + condition;
		System.out.println("contentSql: " + contentSql);
		return contentSql;
	}
	
	public String getData(Set<Role> rs, int appId) {
		try {
			Class<T> c = this.getGenericType();
			String headSql = "select t.field from role r, role_tableinfo_auth rt, table_info t ";
			headSql += "where r.id = rt.role_id and rt.tableinfo_id = t.id ";
			headSql += "and rt.visibility = 1 and t.table = ? and ";
			String condition = "r.id in (";
			Iterator<Role> it = rs.iterator();
			while(it.hasNext()) {
				condition += it.next().getId() + ",";
			}
			condition = condition.substring(0, condition.length() - 1);
			headSql = headSql + condition + ")";
			System.out.println("headSql: " + headSql);
			String tableName = EntityTableMapping.getTableOrFieldName(c.getConstructor());
			List<Map<String, Object>> list = getJdbcTemplate().queryForList(headSql, tableName);
			String[] heads = new String[list.size() + 1];
			heads[0] = EntityTableMapping.getTableId(c);
			int i = 1;
			for(Map<String, Object> map: list) {
				heads[i++] = map.get("field") + "";
			}
			
			List<T> datas = new ArrayList<T>();
			if(heads.length > 1) {
				String contentSql = this.getContentSql(tableName, heads, "");
				datas = getJdbcTemplate().query(contentSql, new Object[]{}, new EntityRowMapper<T>(c, heads));
			}
			System.out.println(datas);
			
			String functionSql = "SELECT a.name, a.url, ra.visibility, ra.usability, a.type ";
			functionSql += "FROM role r, role_app_auth ra, app a ";
			functionSql += "WHERE r.id = ra.role_id AND ra.app_id = a.id AND a.pid = ? and r.id in (";
			it = rs.iterator();
			condition = "";
			while(it.hasNext()) {
				condition += it.next().getId() + ",";
			}
			functionSql = functionSql + condition.substring(0, condition.length() - 1) + ")";
			System.out.println("functionSql: " + functionSql);
			List<Map<String, Object>> functions = this.getJdbcTemplate().queryForList(functionSql, appId);
			return createXML(heads, datas, functions);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "";
		}
	}

	public void delete(int id) {
		Class<T> c = this.getGenericType();
		String table;
		try {
			table = EntityTableMapping.getTableOrFieldName(c.getConstructor());
			String tid = EntityTableMapping.getTableId(c);
			String sql = "delete from " + table + " where " + tid + " = ?";
			this.getJdbcTemplate().update(sql, id);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public Object add(Set<Role> rs) {
		/*HashMap<String, String> map1 = new HashMap<String, String>();
		HashMap<String, String> map2 = new HashMap<String, String>();
		
		map1.put("name", "a");
		map1.put("age", "12");
		
		map2.put("name", "ab");
		map2.put("age", "123");
		
		list.add(map1);
		list.add(map2);*/
		Class<T> c = this.getGenericType();
		String headSql = "select t.field,t.type from role r, role_tableinfo_auth rt, table_info t ";
		headSql += "where r.id = rt.role_id and rt.tableinfo_id = t.id ";
		headSql += "and rt.visibility = 1 and t.table = ? and ";
		String condition = "r.id in (";
		Iterator<Role> it = rs.iterator();
		while(it.hasNext()) {
			condition += it.next().getId() + ",";
		}
		condition = condition.substring(0, condition.length() - 1);
		headSql = headSql + condition + ")";
		System.out.println("addFieldSql: " + headSql);
		String tableName = null;
		try {
			tableName = EntityTableMapping.getTableOrFieldName(c.getConstructor());
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		List<Map<String, Object>> list = getJdbcTemplate().queryForList(headSql, tableName);
		return list;
	}

}
